﻿// <copyright file="BaseImporter.cs" company="Gravity Age Studios">
// Code released under the MIT license (see License.txt).
// </copyright>
// <author>Vicente Cartas Espinel</author>
// <email>vicente.cartas@gmail.com</email>
namespace LightSwitchApplication.Import
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using Microsoft.LightSwitch;
    using Microsoft.LightSwitch.Framework;
    using Microsoft.LightSwitch.Framework.Client;

    public abstract class BaseImporter<T> where T : class, IEntityObject
    {
        protected DataWorkspace workspace;

        protected Func<T> builder;

        protected int?[] headers;

        protected string[] data;

        protected IEnumerable<T> entities;

        protected BaseImporter(DataWorkspace workspace)
        {
            this.workspace = workspace;
        }

        public void ImportData(Stream stream, bool useDispatcher = true)
        {
            if (useDispatcher)
            {
                this.workspace.Details.Dispatcher.BeginInvoke(() =>
                {
                    this.Initialize();
                    this.FetchRequisites();

                    using (StreamReader reader = new StreamReader(stream))
                    {
                        string[] stringHeaders = reader.ReadLine().Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);
                        this.headers = this.MapHeaders(stringHeaders);

                        int rowLength = stringHeaders.Length;
                        this.data = reader.ReadToEnd().Split(new string[] { ";", Environment.NewLine }, StringSplitOptions.None);

                        for (int i = 0; i < this.data.Length - 1; i += rowLength)
                        {
                            try
                            {
                                if (!this.SkipEntity(i))
                                {
                                    this.FillEntity(this.builder(), i, this.headers, this.data);
                                }
                            }
                            catch (Exception)
                            {
                            }
                        }
                    }
                });
            }
            else
            {
                this.Initialize();
                this.FetchRequisites();

                using (StreamReader reader = new StreamReader(stream))
                {
                    string[] stringHeaders = reader.ReadLine().Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);
                    this.headers = this.MapHeaders(stringHeaders);

                    int rowLength = stringHeaders.Length;
                    this.data = reader.ReadToEnd().Split(new string[] { ";", Environment.NewLine }, StringSplitOptions.None);

                    for (int i = 0; i < this.data.Length - 1; i += rowLength)
                    {
                        try
                        {
                            if (!this.SkipEntity(i))
                            {
                                this.FillEntity(this.builder(), i, this.headers, this.data);
                            }
                        }
                        catch (Exception)
                        {
                        }
                    }
                }
            }
        }

        protected virtual void FetchRequisites()
        {
        }

        protected abstract int?[] MapHeaders(string[] stringHeaders);

        //protected abstract void ValidateHeaders(int?[] headers);

        protected abstract bool SkipEntity(int index);

        protected abstract void FillEntity(T entity, int index, int?[] headers, string[] data);

        private void Initialize()
        {
            EntitySet<T> set = (EntitySet<T>)workspace.ApplicationData
                .GetType()
                .GetProperties()
                .First(p => p.CanRead && p.PropertyType.Equals(typeof(EntitySet<T>)))
                .GetValue(workspace.ApplicationData, null);

            this.builder = () => set.AddNew();
            this.entities = set.GetQuery().Execute();
        }
    }
}
